package jlib.component.button
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	public class FrameButton extends MovieClip implements IButton
	{
		protected var m_map:Object;
		private var m_delegate:MovieClip;
		
		private var m_strategy:IButtonStrategy;
		private var m_buttonStrategy:IButtonStrategy;
		private var m_toggleStrategy:IButtonStrategy;
		
		private var m_enabled:Boolean;
		private var m_isToggle:Boolean;
		
		public function FrameButton(wrappee:MovieClip=null): void {
			super();
			m_enabled = true;
			m_map = new Object;
			m_buttonStrategy = new DefaultStrategy(this);
			setToggle(false);
			buttonMode = true;
			if(wrappee) setWrappee(wrappee);
		}
		
		/**
		 * 릴리즈 프레임 영역 startFrame~endFrame 까지
		 * @param startFrame 시작할 프레임
		 * @param endFrame 정지할 프레임
		 */
		public function setUp(startFrame:Object, endFrame:int): void { addEvent(ButtonState.UP, startFrame, endFrame); }
		/**
		 * 프레스 프레임 영역 startFrame~endFrame 까지
		 * @param startFrame 시작할 프레임
		 * @param endFrame 정지할 프레임
		 */
		public function setDown(startFrame:Object, endFrame:int): void { addEvent(ButtonState.DOWN, startFrame, endFrame); }
		/**
		 * 롤오버 프레임 영역 startFrame~endFrame 까지
		 * @param startFrame 시작할 프레임
		 * @param endFrame 정지할 프레임
		 */
		public function setRollOver(startFrame:Object, endFrame:int): void { addEvent(ButtonState.ROLLOVER, startFrame, endFrame); }
		/**
		 * 롤아웃 프레임 영역 startFrame~endFrame 까지
		 * @param startFrame 시작할 프레임
		 * @param endFrame 정지할 프레임
		 */
		public function setRollOut(startFrame:Object, endFrame:int): void { addEvent(ButtonState.ROLLOUT, startFrame, endFrame); }
		
		private function addEvent($state:String, startFrame:Object, endFrame:int ): void {
			m_map[$state] = new FrameVO(startFrame, endFrame-1);
			m_delegate.addEventListener(MouseEvent.CLICK, click );
			if($state == ButtonState.DOWN) m_delegate.addEventListener(MouseEvent.MOUSE_DOWN, down );
			if($state == ButtonState.ROLLOVER) m_delegate.addEventListener(MouseEvent.ROLL_OVER, rollOver );
			if($state == ButtonState.ROLLOUT) m_delegate.addEventListener(MouseEvent.ROLL_OUT, rollOut );
			if($state == ButtonState.UP) m_delegate.addEventListener(MouseEvent.MOUSE_UP, up );
			if(hasState(ButtonState.UP)) view(ButtonState.UP);
			_setChildOption(m_map[$state]);
		}
		
		/* templete method */
		protected function _setChildOption(frameVO:FrameVO): void  { m_delegate.addFrameScript(frameVO.getEnd(), m_delegate.stop); }
		
		private function run(frameVO:FrameVO): void {
			if(!frameVO) return;
			if(frameVO.getStart() == frameVO.getEnd()+1) m_delegate.gotoAndStop(frameVO.getStart()); 
			else m_delegate.gotoAndPlay(frameVO.getStart());
		}
		
		public function setToggle(boolean:Boolean): void {
			m_isToggle = boolean;
			if(boolean) {
				if(!m_toggleStrategy) m_toggleStrategy = new ToggleStrategy(this);
				changeStratey(m_toggleStrategy);
			} else changeStratey(m_buttonStrategy);
		}
		
		public function down(e:Event=null): void {
			if(!m_enabled) return ;
			m_strategy.down(e);
			if(m_delegate.stage) {
				m_delegate.stage.addEventListener(MouseEvent.MOUSE_UP, outside );
				m_delegate.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
				m_delegate.removeEventListener(MouseEvent.ROLL_OVER, rollOver );
				m_delegate.removeEventListener(MouseEvent.ROLL_OUT, rollOut );
			}
			if(m_delegate != this && !contains(m_delegate)) {
				if(!e) e = new MouseEvent(MouseEvent.MOUSE_DOWN);
				dispatchEvent(e);
			}
		}
		
		public function up(e:Event=null): void {
			if(!m_enabled) return ;
			m_strategy.up(e);
			if(m_delegate != this && !contains(m_delegate)) {
				if(!e) e = new MouseEvent(MouseEvent.MOUSE_UP);
				dispatchEvent(e);
			}
		}
		
		public function click(e:Event=null): void {
			if(!m_enabled) return ;
			m_strategy.click(e);
			if(m_delegate != this && !contains(m_delegate)) {
				if(!e) e = new MouseEvent(MouseEvent.CLICK);
				dispatchEvent(e);
			}
		}
		
		public function toggle(e:Event=null): void {
			if(!m_enabled) return ;
			click();
		}
		
		private function rollOver(e:Event=null): void {
			if(!m_enabled) return ;
			if(m_delegate.hasEventListener(MouseEvent.ROLL_OUT)){
				if(m_delegate.stage) m_delegate.stage.addEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
			}
			m_strategy.rollOver(e);
			if(m_delegate != this && !contains(m_delegate)) {
				if(!e) e = new MouseEvent(MouseEvent.ROLL_OVER);
				dispatchEvent(e);
			}
		}
		
		private function rollOut(e:Event=null): void {
			if(!m_enabled) return ;
			m_delegate.removeEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
			m_strategy.rollOut(e);
			if(m_delegate != this && !contains(m_delegate)) {
				if(!e) e = new MouseEvent(MouseEvent.ROLL_OUT);
				dispatchEvent(e);
			}
		}
		
		private function outside(e:Event=null): void {
			if(!m_enabled) return ;
			m_strategy.outside(e);
			if(m_delegate.stage) {
				m_delegate.stage.removeEventListener(MouseEvent.MOUSE_UP, outside );
				m_delegate.addEventListener(MouseEvent.ROLL_OVER, rollOver );
				m_delegate.addEventListener(MouseEvent.ROLL_OUT, rollOut );
				m_delegate.dispatchEvent(new Event(MouseEvent.MOUSE_UP));
			}
		}
		
		public function changeStratey($buttonStrategy:IButtonStrategy): void {
			m_strategy = $buttonStrategy;
		}
		
		private function onCheckOutside($event:Event): void {
			if(m_delegate != $event.target) {
				m_delegate.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onCheckOutside );
				rollOut($event);
			}
		}
		
		override public function set mouseEnabled(enabled:Boolean) : void {
			m_enabled = enabled;
			m_delegate.mouseEnabled = enabled;
			super.mouseEnabled = enabled;
		}	
		
		public function view($state:String): void { run(m_map[$state]); }
		
		public function hasState($state:String): Boolean { return Boolean(m_map[$state]); }
		
		public function getWrappee(): MovieClip { return m_delegate; }
		/**
		 * 프레임버튼의 대상이 될 객체 버튼을 대체할 혹은 감쌀 수 있는
		 * @param movieClip 대상 무비클립
		 */	
		public function setWrappee(movieClip:MovieClip): void  { m_delegate = movieClip; }
		
		public function isTogglable():Boolean  {  return m_isToggle; }
		public function isSelected():Boolean  {  return m_strategy.isSelected(); }
		
		override public function get mouseChildren():Boolean { return m_delegate.mouseChildren; }
		
		override public function set mouseChildren(enable:Boolean): void {
			m_delegate.mouseChildren = false;
		}

	}//c
}